-/**\r
- Allocates and returns a Null-terminated Unicode <ConfigAltResp> string.\r
-\r
- If Guid is NULL, then ASSERT().\r
- If Name is NULL, then ASSERT().\r
- If BlockNameArray is NULL, then ASSERT().\r
-\r
- @param[in] Guid GUID of the buffer storage.\r
- @param[in] Name Name of the buffer storage.\r
- @param[in] DriverHandle The DriverHandle that support a Device Path\r
- Protocol. \r
- @param[in] BufferStorage Content of the buffer storage.\r
- @param[in] BufferStorageSize Length in bytes of the buffer storage.\r
- @param[in] BlockNameArray Array generated by VFR compiler. This array\r
- contains a UINT32 value that is the length\r
- of BlockNameArray in bytes, followed by pairs\r
- of 16-bit values that are the offset and length\r
- values used to contruct a <ConfigRequest> string.\r
- @param[in] ... A variable argument list that contains pairs of 16-bit\r
- ALTCFG identifiers and pointers to DefaultValueArrays.\r
- The variable argument list is terminated by a NULL \r
- DefaultValueArray pointer. A DefaultValueArray \r
- contains a UINT32 value that is the length, in bytes,\r
- of the DefaultValueArray. The UINT32 length value \r
- is followed by a series of records that contain\r
- a 16-bit WIDTH value followed by a byte array with \r
- WIDTH entries. The records must be parsed from\r
- beginning to end until the UINT32 length limit\r
- is reached. \r
-\r
- @retval NULL There are not enough resources to process the request.\r
- @retval NULL A <ConfigResp> could not be retrieved from the Config \r
- Routing Protocol.\r
- @retval Other A pointer to the Null-terminate Unicode <ConfigAltResp>\r
- string.\r
-\r
-**/\r
-EFI_STRING\r
-EFIAPI\r
-HiiConstructConfigAltResp (\r
- IN CONST EFI_GUID *Guid,\r
- IN CONST CHAR16 *Name,\r
- IN EFI_HANDLE DriverHandle,\r
- IN CONST VOID *BufferStorage,\r
- IN UINTN BufferStorageSize,\r
- IN CONST VOID *BlockNameArray, \r
- ...\r
- )\r
-{\r
- UINTN Length;\r
- CHAR16 *String;\r
- CHAR16 *ConfigHdr;\r
- UINT8 *Buffer;\r
- UINT8 *BufferEnd;\r
- CHAR16 *ConfigRequest;\r
- EFI_STRING ConfigResp;\r
- EFI_STRING ConfigAltResp;\r
- VA_LIST Args;\r
- UINTN AltCfgId;\r
- UINT16 Width;\r
- UINT16 OffsetValue;\r
- UINT16 WidthValue;\r
-\r
- ASSERT (Guid != NULL);\r
- ASSERT (Name != NULL);\r
- ASSERT (BlockNameArray != NULL);\r
-\r
- //\r
- // Initialize local variables\r
- //\r
- ConfigHdr = NULL;\r
- ConfigRequest = NULL; \r
- ConfigResp = NULL;\r
-\r
- //\r
- // Construct <ConfigHdr> : "GUID=...&NAME=...&PATH=..."\r
- //\r
- ConfigHdr = HiiConstructConfigHdr (Guid, Name, DriverHandle);\r
- if (ConfigHdr == NULL) {\r
- goto Exit;\r
- }\r
-\r
- //\r
- // Compute the length of the entire request starting with <ConfigHdr> and a \r
- // Null-terminator\r
- //\r
- Length = StrLen (ConfigHdr) + 1;\r
-\r
- //\r
- // Determine the size <BlockName> Offset/Width pairs\r
- //\r
- Buffer = (UINT8 *)BlockNameArray;\r
- BufferEnd = Buffer + ReadUnaligned32 ((UINT32 *)Buffer);\r
- Buffer += sizeof (UINT32);\r
-\r
- //\r
- // Add <BlockName> length that is composed of one or more Offset/Width pairs\r
- //\r
- // <BlockName> ::= &OFFSET=1234&WIDTH=1234\r
- // | 8 | 4 | 7 | 4 |\r
- //\r
- Length += (((BufferEnd - Buffer) / (sizeof (UINT16) + sizeof (UINT16))) * (8 + 4 + 7 + 4));\r
-\r
- //\r
- // Allocate buffer for the entire <ConfigRequest>\r
- //\r
- ConfigRequest = AllocateZeroPool (Length * sizeof (CHAR16));\r
- if (ConfigRequest == NULL) {\r
- goto Exit;\r
- }\r
- String = ConfigRequest;\r
-\r
- //\r
- // Start with <ConfigHdr>\r
- //\r
- StrCpy (String, ConfigHdr);\r
- String += StrLen (String);\r
-\r
- //\r
- // Loop through all the Offset/Width pairs and append them to ConfigRequest\r
- //\r
- while (Buffer < BufferEnd) {\r
- //\r
- // Append &OFFSET=XXXX&WIDTH=YYYY\r
- //\r
- OffsetValue = ReadUnaligned16 ((UINT16 *)Buffer);\r
- WidthValue = ReadUnaligned16 ((UINT16 *)(Buffer + sizeof (UINT16)));\r
- UnicodeSPrint (\r
- String, \r
- (8 + 4 + 7 + 4) * sizeof (CHAR16), \r
- L"&OFFSET=%04X&WIDTH=%04X", \r
- OffsetValue, \r
- WidthValue\r
- );\r
-\r
- String += StrLen (String);\r
- Buffer += (sizeof (UINT16) + sizeof (UINT16));\r
- }\r
-\r
- //\r
- // Get the <ConfigResp>\r
- //\r
- ConfigResp = InternalHiiBlockToConfig (ConfigRequest, BufferStorage, BufferStorageSize);\r
- if (ConfigResp == NULL) {\r
- goto Exit;\r
- }\r
-\r
- //\r
- // Compute the length of the entire response starting with <ConfigResp> and a \r
- // Null-terminator\r
- //\r
- Length = StrLen (ConfigResp) + 1;\r
-\r
- //\r
- // Add the length associated with each pair of variable argument parameters\r
- //\r
- VA_START (Args, BlockNameArray);\r
- while (TRUE) {\r
- AltCfgId = VA_ARG (Args, UINTN);\r
- Buffer = VA_ARG (Args, UINT8 *);\r
- if (Buffer == NULL) {\r
- break;\r
- }\r
-\r
- //\r
- // Add length for "&<ConfigHdr>&ALTCFG=XXXX"\r
- // |1| StrLen (ConfigHdr) | 8 | 4 |\r
- //\r
- Length += (1 + StrLen (ConfigHdr) + 8 + 4);\r
-\r
- BufferEnd = Buffer + ReadUnaligned32 ((UINT32 *)Buffer);\r
- Buffer += sizeof (UINT32);\r
- while (Buffer < BufferEnd) {\r
- //\r
- // Extract Width field\r
- //\r
- Width = ReadUnaligned16 ((UINT16 *)(Buffer + sizeof (UINT16)));\r
-\r
- //\r
- // Add length for "&OFFSET=XXXX&WIDTH=YYYY&VALUE=zzzzzzzzzzzz"\r
- // | 8 | 4 | 7 | 4 | 7 | Width * 2 |\r
- //\r
- Length += (8 + 4 + 7 + 4 + 7 + Width * 2);\r
-\r
- //\r
- // Update Buffer to the next record\r
- //\r
- Buffer += (sizeof (UINT16) + sizeof (UINT16) + Width);\r
- }\r
- }\r
- VA_END (Args);\r
-\r
- //\r
- // Allocate a buffer for the entire response\r
- //\r
- ConfigAltResp = AllocateZeroPool (Length * sizeof (CHAR16));\r
- if (ConfigAltResp == NULL) {\r
- goto Exit;\r
- }\r
- String = ConfigAltResp;\r
-\r
- //\r
- // Add <ConfigResp>\r
- //\r
- StrCpy (String, ConfigResp);\r
- String += StrLen (String);\r
-\r
- //\r
- // Add <AltResp> for each pair of variable argument parameters\r
- //\r
- VA_START (Args, BlockNameArray);\r
- while (TRUE) {\r
- AltCfgId = VA_ARG (Args, UINTN);\r
- Buffer = VA_ARG (Args, UINT8 *);\r
- if (Buffer == NULL) {\r
- break;\r
- }\r
-\r
- //\r
- // Add <AltConfigHdr> of the form "&<ConfigHdr>&ALTCFG=XXXX"\r
- // |1| StrLen (ConfigHdr) | 8 | 4 |\r
- //\r
- UnicodeSPrint (\r
- String, \r
- (1 + StrLen (ConfigHdr) + 8 + 4) * sizeof (CHAR16), \r
- L"&%s&ALTCFG=%04X", \r
- ConfigHdr, \r
- AltCfgId\r
- );\r
- String += StrLen (String);\r
-\r
- //\r
- // Add <ConfigBody> ::= <ConfigElement>*\r
- //\r
- BufferEnd = Buffer + ReadUnaligned32 ((UINT32 *)Buffer);\r
- Buffer += sizeof (UINT32);\r
- while (Buffer < BufferEnd) {\r
- //\r
- // Extract Width field\r
- //\r
- Width = ReadUnaligned16 ((UINT16 *)(Buffer + sizeof (UINT16)));\r
-\r
- //\r
- // Add <BlockConfig>\r
- //\r
- UnicodeSPrint (\r
- String, \r
- (8 + 4 + 7 + 4 + 7 + Width * 2) * sizeof (CHAR16),\r
- L"&OFFSET=%04X&WIDTH=%04X&VALUE=", \r
- ReadUnaligned16 ((UINT16 *)Buffer), \r
- Width\r
- );\r
- String += StrLen (String);\r
-\r
- //\r
- // Update Buffer to point to the value in the current record\r
- //\r
- Buffer += (sizeof (UINT16) + sizeof (UINT16));\r
-\r
- //\r
- // Convert Value to a hex string in "%x" format\r
- // NOTE: This is in the opposite byte that GUID and PATH use\r
- //\r
- for (; Width > 0; Width--) {\r
- String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, Buffer[Width - 1], 2);\r
- }\r
- //\r
- // Update Buffer to the next record\r
- //\r
- Buffer += Width;\r
- }\r
- }\r
- VA_END (Args);\r
-\r
- //\r
- // Convert all hex digits in range [A-F] in the configuration header to [a-f]\r
- //\r
- return InternalHiiLowerConfigString (ConfigAltResp);\r
-\r
-Exit:\r
- if (ConfigHdr != NULL) {\r
- FreePool (ConfigHdr);\r
- }\r
- if (ConfigRequest != NULL) {\r
- FreePool (ConfigRequest);\r
- }\r
- if (ConfigResp != NULL) {\r
- FreePool (ConfigResp);\r
- }\r
-\r
- return NULL;\r
-}\r
-\r