+typedef enum {\r
+ DataTypeHexNumber = 0,\r
+ DataTypeHexArray = 1,\r
+ DataTypeAscii = 2,\r
+ DataTypeUnicode = 3,\r
+ DataTypeDevicePath = 4,\r
+ DataTypeUnKnow = 5\r
+} DATA_TYPE;\r
+\r
+typedef union {\r
+ UINT8 HexNumber8;\r
+ UINT16 HexNumber16;\r
+ UINT32 HexNumber32;\r
+ UINT64 HexNumber64;\r
+} HEX_NUMBER;\r
+\r
+/**\r
+ Check if the input is a (potentially empty) string of hexadecimal nibbles.\r
+\r
+ @param[in] String The CHAR16 string to check.\r
+\r
+ @retval FALSE A character has been found in String for which\r
+ ShellIsHexaDecimalDigitCharacter() returned FALSE.\r
+\r
+ @retval TRUE Otherwise. (Note that this covers the case when String is\r
+ empty.)\r
+**/\r
+BOOLEAN\r
+IsStringOfHexNibbles (\r
+ IN CONST CHAR16 *String\r
+ )\r
+{\r
+ CONST CHAR16 *Pos;\r
+\r
+ for (Pos = String; *Pos != L'\0'; ++Pos) {\r
+ if (!ShellIsHexaDecimalDigitCharacter (*Pos)) {\r
+ return FALSE;\r
+ }\r
+ }\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Function to check the TYPE of Data.\r
+\r
+ @param[in] Data The Data to be check.\r
+\r
+ @retval DATA_TYPE The TYPE of Data.\r
+**/\r
+DATA_TYPE\r
+TestDataType (\r
+ IN CONST CHAR16 *Data\r
+ )\r
+{\r
+ if (Data[0] == L'0' && (Data[1] == L'x' || Data[1] == L'X')) {\r
+ if (IsStringOfHexNibbles (Data+2) && StrLen (Data + 2) <= 16) {\r
+ return DataTypeHexNumber;\r
+ } else {\r
+ return DataTypeUnKnow;\r
+ }\r
+ } else if (Data[0] == L'H') {\r
+ if (IsStringOfHexNibbles (Data + 1) && StrLen (Data + 1) % 2 == 0) {\r
+ return DataTypeHexArray;\r
+ } else {\r
+ return DataTypeUnKnow;\r
+ }\r
+ } else if (Data[0] == L'S') {\r
+ return DataTypeAscii;\r
+ } else if (Data[0] == L'L') {\r
+ return DataTypeUnicode;\r
+ } else if (Data[0] == L'P' || StrnCmp (Data, L"--", 2) == 0) {\r
+ return DataTypeDevicePath;\r
+ }\r
+\r
+ if (IsStringOfHexNibbles (Data) && StrLen (Data) % 2 == 0) {\r
+ return DataTypeHexArray;\r
+ }\r
+\r
+ return DataTypeAscii;\r
+}\r
+\r
+/**\r
+ Function to parse the Data by the type of Data, and save in the Buffer.\r
+\r
+ @param[in] Data A pointer to a buffer to be parsed.\r
+ @param[out] Buffer A pointer to a buffer to hold the return data.\r
+ @param[in,out] BufferSize On input, indicates the size of Buffer in bytes.\r
+ On output,indicates the size of data return in Buffer.\r
+ Or the size in bytes of the buffer needed to obtain.\r
+\r
+ @retval EFI_INVALID_PARAMETER The Buffer or BufferSize is NULL.\r
+ @retval EFI_BUFFER_TOO_SMALL The Buffer is too small to hold the data.\r
+ @retval EFI_OUT_OF_RESOURCES A memory allcation failed.\r
+ @retval EFI_SUCCESS The Data parsed successful and save in the Buffer.\r
+**/\r
+EFI_STATUS\r
+ParseParameterData (\r
+ IN CONST CHAR16 *Data,\r
+ OUT VOID *Buffer,\r
+ IN OUT UINTN *BufferSize\r
+ )\r
+{\r
+ UINT64 HexNumber;\r
+ UINTN HexNumberLen;\r
+ UINTN Size;\r
+ CHAR8 *AsciiBuffer;\r
+ DATA_TYPE DataType;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
+ EFI_STATUS Status;\r
+\r
+ HexNumber = 0;\r
+ HexNumberLen = 0;\r
+ Size = 0;\r
+ AsciiBuffer = NULL;\r
+ DevPath = NULL;\r
+ Status = EFI_SUCCESS;\r
+\r
+ if (Data == NULL || BufferSize == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ DataType = TestDataType (Data);\r
+ if (DataType == DataTypeHexNumber) {\r
+ //\r
+ // hex number\r
+ //\r
+ StrHexToUint64S (Data + 2, NULL, &HexNumber);\r
+ HexNumberLen = StrLen (Data + 2);\r
+ if (HexNumberLen >= 1 && HexNumberLen <= 2) {\r
+ Size = 1;\r
+ } else if (HexNumberLen >= 3 && HexNumberLen <= 4) {\r
+ Size = 2;\r
+ } else if (HexNumberLen >= 5 && HexNumberLen <= 8) {\r
+ Size = 4;\r
+ } else if (HexNumberLen >= 9 && HexNumberLen <= 16) {\r
+ Size = 8;\r
+ }\r
+ if (Buffer != NULL && *BufferSize >= Size) {\r
+ CopyMem(Buffer, (VOID *)&HexNumber, Size);\r
+ } else {\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ }\r
+ *BufferSize = Size;\r
+ } else if (DataType == DataTypeHexArray) {\r
+ //\r
+ // hex array\r
+ //\r
+ if (*Data == L'H') {\r
+ Data = Data + 1;\r
+ }\r
+\r
+ Size = StrLen (Data) / 2;\r
+ if (Buffer != NULL && *BufferSize >= Size) {\r
+ StrHexToBytes(Data, StrLen (Data), (UINT8 *)Buffer, Size);\r
+ } else {\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ }\r
+ *BufferSize = Size;\r
+ } else if (DataType == DataTypeAscii) {\r
+ //\r
+ // ascii text\r
+ //\r
+ if (*Data == L'S') {\r
+ Data = Data + 1;\r
+ }\r
+ AsciiBuffer = AllocateZeroPool (StrSize (Data) / 2);\r
+ if (AsciiBuffer == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ } else {\r
+ AsciiSPrint (AsciiBuffer, StrSize (Data) / 2, "%s", (CHAR8 *)Data);\r
+\r
+ Size = StrSize (Data) / 2 - 1;\r
+ if (Buffer != NULL && *BufferSize >= Size) {\r
+ CopyMem (Buffer, AsciiBuffer, Size);\r
+ } else {\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ }\r
+ *BufferSize = Size;\r
+ }\r
+ SHELL_FREE_NON_NULL (AsciiBuffer);\r
+ } else if (DataType == DataTypeUnicode) {\r
+ //\r
+ // unicode text\r
+ //\r
+ if (*Data == L'L') {\r
+ Data = Data + 1;\r
+ }\r
+ Size = StrSize (Data) - sizeof (CHAR16);\r
+ if (Buffer != NULL && *BufferSize >= Size) {\r
+ CopyMem (Buffer, Data, Size);\r
+ } else {\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ }\r
+ *BufferSize = Size;\r
+ } else if (DataType == DataTypeDevicePath) {\r
+ if (*Data == L'P') {\r
+ Data = Data + 1;\r
+ } else if (StrnCmp (Data, L"--", 2) == 0) {\r
+ Data = Data + 2;\r
+ }\r
+ DevPath = ConvertTextToDevicePath (Data);\r
+ if (DevPath == NULL) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SETVAR_ERROR_DPFT), gShellDebug1HiiHandle, L"setvar");\r
+ Status = EFI_INVALID_PARAMETER;\r
+ } else {\r
+ Size = GetDevicePathSize (DevPath);\r
+ if (Buffer != NULL && *BufferSize >= Size) {\r
+ CopyMem (Buffer, DevPath, Size);\r
+ } else {\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ }\r
+ *BufferSize = Size;\r
+ }\r
+ SHELL_FREE_NON_NULL (DevPath);\r
+ } else {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Function to get each data from parameters.\r
+\r
+ @param[in] Package The package of checked values.\r
+ @param[out] Buffer A pointer to a buffer to hold the return data.\r
+ @param[out] BufferSize Indicates the size of data in bytes return in Buffer.\r
+\r
+ @retval EFI_INVALID_PARAMETER Buffer or BufferSize is NULL.\r
+ @retval EFI_OUT_OF_RESOURCES A memory allcation failed.\r
+ @retval EFI_SUCCESS Get each parameter data was successful.\r
+**/\r
+EFI_STATUS\r
+GetVariableDataFromParameter (\r
+ IN CONST LIST_ENTRY *Package,\r
+ OUT UINT8 **Buffer,\r
+ OUT UINTN *BufferSize\r
+ )\r
+{\r
+ CONST CHAR16 *TempData;\r
+ UINTN Index;\r
+ UINTN TotalSize;\r
+ UINTN Size;\r
+ UINT8 *BufferWalker;\r
+ EFI_STATUS Status;\r
+\r
+ TotalSize = 0;\r
+ Size = 0;\r
+ Status = EFI_SUCCESS;\r
+\r
+ if (BufferSize == NULL || Buffer == NULL || ShellCommandLineGetCount (Package) < 3) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ for (Index = 2; Index < ShellCommandLineGetCount (Package); Index++) {\r
+ TempData = ShellCommandLineGetRawValue (Package, Index);\r
+ ASSERT (TempData != NULL);\r
+\r
+ if (TempData[0] != L'=') {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"setvar", TempData);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ TempData = TempData + 1;\r
+ Size = 0;\r
+ Status = ParseParameterData (TempData, NULL, &Size);\r
+ if (EFI_ERROR (Status)) {\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ //\r
+ // We expect return EFI_BUFFER_TOO_SMALL when pass 'NULL' as second parameter to the function ParseParameterData.\r
+ //\r
+ TotalSize += Size;\r
+ } else {\r
+ if (Status == EFI_INVALID_PARAMETER) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"setvar", TempData);\r
+ } else if (Status == EFI_NOT_FOUND) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SETVAR_ERROR_DPFT), gShellDebug1HiiHandle, L"setvar");\r
+ }\r
+ return Status;\r
+ }\r
+ }\r
+ }\r
+\r
+ *BufferSize = TotalSize;\r
+ *Buffer = AllocateZeroPool (TotalSize);\r
+\r
+ if (*Buffer == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ } else {\r
+ BufferWalker = *Buffer;\r
+ for (Index = 2; Index < ShellCommandLineGetCount (Package); Index++) {\r
+ TempData = ShellCommandLineGetRawValue (Package, Index);\r
+ TempData = TempData + 1;\r
+\r
+ Size = TotalSize;\r
+ Status = ParseParameterData (TempData, (VOID *)BufferWalker, &Size);\r
+ if (!EFI_ERROR (Status)) {\r
+ BufferWalker = BufferWalker + Size;\r
+ TotalSize = TotalSize - Size;\r
+ } else {\r
+ return Status;\r
+ }\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r