/** @file Implementation of interfaces function for EFI_HII_CONFIG_ROUTING_PROTOCOL. ;****************************************************************************** ;* Copyright (c) 2012 - 2021, Insyde Software Corp. All Rights Reserved. ;* ;* You may not reproduce, distribute, publish, display, perform, modify, adapt, ;* transmit, broadcast, present, recite, release, license or otherwise exploit ;* any part of this publication in any form, by any means, without the prior ;* written permission of Insyde Software Corporation. ;* ;****************************************************************************** Copyright (c) 2007 - 2012, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. */ #include "HiiDatabase.h" extern HII_DATABASE_PRIVATE_DATA mPrivate; #define STRLEN(x) ((sizeof (x) / sizeof (CHAR16)) - 1) #define StrnCmp HiiStrnCmp #define StrHexToUint64 HiiStrHexToUint64 INTN EFIAPI HiiStrnCmp ( IN CONST CHAR16 *FirstString, IN CONST CHAR16 *SecondString, IN UINTN Length ) { if (Length == 0) { return 0; } // // ASSERT both strings are less long than PcdMaximumUnicodeStringLength. // Length tests are performed inside StrLen(). // //ASSERT (StrSize (FirstString) != 0); //ASSERT (StrSize (SecondString) != 0); // // if (PcdGet32 (PcdMaximumUnicodeStringLength) != 0) { // ASSERT (Length <= PcdGet32 (PcdMaximumUnicodeStringLength)); // } ASSERT (FirstString != NULL); ASSERT (SecondString != NULL); while ((*FirstString != L'\0') && (*FirstString == *SecondString) && (Length > 1)) { FirstString++; SecondString++; Length--; } return *FirstString - *SecondString; } STATIC CHAR16 EFIAPI InternalCharToUpper ( IN CHAR16 Char ) { if (Char >= L'a' && Char <= L'z') { return (CHAR16) (Char - (L'a' - L'A')); } return Char; } STATIC BOOLEAN EFIAPI InternalIsDecimalDigitCharacter ( IN CHAR16 Char ) { return (BOOLEAN) (Char >= L'0' && Char <= L'9'); } STATIC UINTN EFIAPI InternalHexCharToUintn ( IN CHAR16 Char ) { if (InternalIsDecimalDigitCharacter (Char)) { return Char - L'0'; } return (UINTN) (10 + InternalCharToUpper (Char) - L'A'); } STATIC BOOLEAN EFIAPI InternalIsHexaDecimalDigitCharacter ( IN CHAR16 Char ) { return (BOOLEAN) (InternalIsDecimalDigitCharacter (Char) || (Char >= L'A' && Char <= L'F') || (Char >= L'a' && Char <= L'f')); } UINT64 EFIAPI HiiStrHexToUint64 ( IN CONST CHAR16 *String ) { UINT64 Result; // // ASSERT String is less long than PcdMaximumUnicodeStringLength. // Length tests are performed inside StrLen(). // //ASSERT (StrSize (String) != 0); // // Ignore the pad spaces (space or tab) // while ((*String == L' ') || (*String == L'\t')) { String++; } // // Ignore leading Zeros after the spaces // while (*String == L'0') { String++; } if (InternalCharToUpper (*String) == L'X') { ASSERT (*(String - 1) == L'0'); if (*(String - 1) != L'0') { return 0; } // // Skip the 'X' // String++; } Result = 0; while (InternalIsHexaDecimalDigitCharacter (*String)) { // // If the Hex Number represented by String overflows according // to the range defined by UINTN, then ASSERT(). // ASSERT (Result <= RShiftU64 (((UINT64) ~0) - InternalHexCharToUintn (*String) , 4)); Result = LShiftU64 (Result, 4); Result = Result + InternalHexCharToUintn (*String); String++; } return Result; } /** Calculate the number of Unicode characters of the incoming Configuration string, not including NULL terminator. This is a internal function. @param[in] String String in or format. @return The number of Unicode characters. **/ UINTN CalculateConfigStringLen ( IN EFI_STRING String ) { EFI_STRING TmpPtr; // // "GUID=" should be the first element of incoming string. // ASSERT (String != NULL); ASSERT (StrnCmp (String, L"GUID=", StrLen (L"GUID=")) == 0); // // The beginning of next / should be "&GUID=". // Will meet '\0' if there is only one /. // TmpPtr = StrStr (String, L"&GUID="); if (TmpPtr == NULL) { return StrLen (String); } return (TmpPtr - String); } /** Convert the hex UNICODE %02x encoding of a UEFI device path to binary from of . This is a internal function. @param[in] String UEFI configuration string @param[out] DevicePathData Binary of a UEFI device path. @retval EFI_NOT_FOUND The device path is not invalid. @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid. @retval EFI_OUT_OF_RESOURCES Lake of resources to store neccesary structures. @retval EFI_SUCCESS The device path is retrieved and translated to binary format. **/ EFI_STATUS GetDevicePath ( IN EFI_STRING String, OUT UINT8 **DevicePathData ) { UINTN Length; EFI_STRING PathHdr; UINT8 *DevicePathBuffer; CHAR16 TemStr[2]; UINTN Index; UINT8 DigitUint8; EFI_DEVICE_PATH_PROTOCOL *DevicePath; if (String == NULL || DevicePathData == NULL) { return EFI_INVALID_PARAMETER; } // // Find the 'PATH=' of and skip it. // for (; (*String != 0 && StrnCmp (String, L"PATH=", StrLen (L"PATH=")) != 0); String++); if (*String == 0) { return EFI_INVALID_PARAMETER; } // // Check whether path data does exist. // String += StrLen (L"PATH="); if (*String == 0) { return EFI_INVALID_PARAMETER; } PathHdr = String; // // The content between 'PATH=' of and '&' of next element // or '\0' (end of configuration string) is the UNICODE %02x bytes encoding // of UEFI device path. // for (Length = 0; *String != 0 && *String != L'&'; String++, Length++); // // Check DevicePath Length // if (((Length + 1) / 2) < sizeof (EFI_DEVICE_PATH_PROTOCOL)) { return EFI_NOT_FOUND; } // // The data in is encoded as hex UNICODE %02x bytes in the same order // as the device path resides in RAM memory. // Translate the data into binary. // DevicePathBuffer = (UINT8 *) AllocateZeroPool ((Length + 1) / 2); if (DevicePathBuffer == NULL) { return EFI_OUT_OF_RESOURCES; } // // Convert DevicePath // ZeroMem (TemStr, sizeof (TemStr)); for (Index = 0; Index < Length; Index ++) { TemStr[0] = PathHdr[Index]; DigitUint8 = (UINT8) StrHexToUint64 (TemStr); if ((Index & 1) == 0) { DevicePathBuffer [Index/2] = DigitUint8; } else { DevicePathBuffer [Index/2] = (UINT8) ((DevicePathBuffer [Index/2] << 4) + DigitUint8); } } // // Validate DevicePath // DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) DevicePathBuffer; while (!IsDevicePathEnd (DevicePath)) { if ((DevicePath->Type == 0) || (DevicePath->SubType == 0) || (DevicePathNodeLength (DevicePath) < sizeof (EFI_DEVICE_PATH_PROTOCOL))) { // // Invalid device path // FreePool (DevicePathBuffer); return EFI_NOT_FOUND; } DevicePath = NextDevicePathNode (DevicePath); } // // return the device path // *DevicePathData = DevicePathBuffer; return EFI_SUCCESS; } /** Converts the unicode character of the string from uppercase to lowercase. This is a internal function. @param[in] ConfigString String to be converted **/ VOID EFIAPI HiiToLower ( IN EFI_STRING ConfigString ) { EFI_STRING String; BOOLEAN Lower; ASSERT (ConfigString != NULL); // // Convert all hex digits in range [A-F] in the configuration header to [a-f] // for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) { if (*String == L'=') { Lower = TRUE; } else if (*String == L'&') { Lower = FALSE; } else if (Lower && *String >= L'A' && *String <= L'F') { *String = (CHAR16) (*String - L'A' + L'a'); } } return; } /** Generate a sub string then output it. This is a internal function. @param[in] String A constant string which is the prefix of the to be generated string, e.g. GUID= @param[in] BufferLen The length of the Buffer in bytes. @param[in] Buffer Points to a buffer which will be converted to be the content of the generated string. @param[in] Flag If 1, the buffer contains data for the value of GUID or PATH stored in UINT8 *; if 2, the buffer contains unicode string for the value of NAME; if 3, the buffer contains other data. @param[out] SubStr Points to the output string. It's caller's responsibility to free this buffer. **/ VOID GenerateSubStr ( IN CONST EFI_STRING String, IN UINTN BufferLen, IN VOID *Buffer, IN UINT8 Flag, OUT EFI_STRING *SubStr ) { UINTN Length; EFI_STRING Str; EFI_STRING StringHeader; CHAR16 *TemString; CHAR16 *TemName; UINT8 *TemBuffer; UINTN Index; ASSERT (String != NULL && SubStr != NULL); if (Buffer == NULL) { *SubStr = AllocateCopyPool (StrSize (String), String); ASSERT (*SubStr != NULL); return ; } // // Header + Data + '&' + '\0' // Length = StrLen (String) + BufferLen * 2 + 1 + 1; Str = AllocateZeroPool (Length * sizeof (CHAR16)); ASSERT (Str != NULL); if (Str == NULL) { return ; } StrCpyS (Str, Length, String); StringHeader = Str + StrLen (String); TemString = (CHAR16 *) StringHeader; switch (Flag) { case 1: // // Convert Buffer to Hex String in reverse order // TemBuffer = ((UINT8 *) Buffer); for (Index = 0; Index < BufferLen; Index ++, TemBuffer ++) { UnicodeValueToStringS ( TemString, sizeof (CHAR16) * (Length - StrnLenS (Str, Length)), PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2 ); TemString += StrnLenS (TemString, Length - StrnLenS (Str, Length)); } break; case 2: // // Check buffer is enough // TemName = (CHAR16 *) Buffer; ASSERT ((BufferLen * 2 + 1) >= (StrLen (TemName) * 4 + 1)); // // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044" // for (; *TemName != L'\0'; TemName++) { UnicodeValueToStringS ( TemString, sizeof (CHAR16) * (Length - StrnLenS (Str, Length)), PREFIX_ZERO | RADIX_HEX, *TemName, 4 ); TemString += StrnLenS (TemString, Length - StrnLenS (Str, Length)); } break; case 3: // // Convert Buffer to Hex String // TemBuffer = ((UINT8 *) Buffer) + BufferLen - 1; for (Index = 0; Index < BufferLen; Index ++, TemBuffer --) { UnicodeValueToStringS ( TemString, sizeof (CHAR16) * (Length - StrnLenS (Str, Length)), PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2 ); TemString += StrnLenS (TemString, Length - StrnLenS (Str, Length)); } break; default: break; } // // Convert the uppercase to lowercase since is defined in lowercase format. // StrCatS (Str, Length, L"&"); HiiToLower (Str); *SubStr = Str; } /** Retrieve the from String then output it. This is a internal function. @param[in] String A sub string of a configuration string in format. @param[out] ConfigBody Points to the output string. It's caller's responsibility to free this buffer. @retval EFI_INVALID_PARAMETER There is no form package in current hii database. @retval EFI_OUT_OF_RESOURCES Not enough memory to finish this operation. @retval EFI_SUCCESS All existing storage is exported. **/ EFI_STATUS OutputConfigBody ( IN EFI_STRING String, OUT EFI_STRING *ConfigBody ) { EFI_STRING TmpPtr; EFI_STRING Result; UINTN Length; if (String == NULL || ConfigBody == NULL) { return EFI_INVALID_PARAMETER; } // // The setting information should start OFFSET, not ALTCFG. // if (StrnCmp (String, L"&ALTCFG=", StrLen (L"&ALTCFG=")) == 0) { return EFI_INVALID_PARAMETER; } TmpPtr = StrStr (String, L"GUID="); if (TmpPtr == NULL) { // // It is the last of the incoming configuration string. // Result = AllocateCopyPool (StrSize (String), String); if (Result == NULL) { return EFI_OUT_OF_RESOURCES; } else { *ConfigBody = Result; return EFI_SUCCESS; } } Length = TmpPtr - String; Result = AllocateCopyPool (Length * sizeof (CHAR16), String); if (Result == NULL) { return EFI_OUT_OF_RESOURCES; } *(Result + Length - 1) = 0; *ConfigBody = Result; return EFI_SUCCESS; } /** Append a string to a multi-string format. This is a internal function. @param[in] MultiString String in , , or . @param[in] AppendString NULL-terminated Unicode string. @param[in, out] BufferSize in: Total buffer size by bytes of input MultiString. out: Total buffer size by bytes of appended configuration string. @param[in, out] UsedSize in: Used buffer size by bytes of input MultiString. out: Used buffer size by bytes of appended configuration string. @return Pointer to appended configuration string. NULL indicates append string failed. **/ EFI_STRING AppendToMultiString ( IN EFI_STRING MultiString, IN EFI_STRING AppendString, IN OUT UINTN *BufferSize, IN OUT UINTN *UsedSize ) { UINTN AppendStringSize; UINTN NewStringSize; UINTN StrEndIndex; if (MultiString == NULL || AppendString == NULL || BufferSize == NULL || UsedSize == NULL) { return NULL; } AppendStringSize = StrSize (AppendString); NewStringSize = AppendStringSize; if (*UsedSize != 0) { NewStringSize += (*UsedSize - sizeof (CHAR16)); } if (NewStringSize > *BufferSize) { MultiString = (EFI_STRING) ReallocatePool ( *UsedSize, NewStringSize << 1, (VOID *) MultiString ); ASSERT (MultiString != NULL); if (MultiString == NULL) { *BufferSize = 0; *UsedSize = 0; return MultiString; } *BufferSize = NewStringSize << 1; } // // Using CopyMem () to append string to prevent from StrCat () spend too much // time if EFI_DEBUG enabled. // StrEndIndex = *UsedSize == 0 ? 0 : *UsedSize / sizeof (CHAR16) - 1; CopyMem (&MultiString[StrEndIndex], AppendString, AppendStringSize); *UsedSize = NewStringSize; return MultiString; } /** Get the value of in format, i.e. the value of OFFSET or WIDTH or VALUE. ::= 'OFFSET='&'WIDTH='&'VALUE'= This is a internal function. @param[in] StringPtr String in format and points to the first character of . @param[out] Number The output value. Caller takes the responsibility to free memory. @param[out] Len Length of the , in characters. @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary structures. @retval EFI_SUCCESS Value of is outputted in Number successfully. **/ EFI_STATUS GetValueOfNumber ( IN EFI_STRING StringPtr, IN OUT UINT8 **Number, IN OUT UINTN *NumberSize, OUT UINTN *Len ) { EFI_STRING TmpPtr; UINTN Length; EFI_STRING Str; UINT8 *Buf; EFI_STATUS Status; UINT8 DigitUint8; UINTN Index; CHAR16 TemStr[2]; CHAR16 StringBuffer[20]; if (StringPtr == NULL || *StringPtr == L'\0' || Number == NULL || Len == NULL) { return EFI_INVALID_PARAMETER; } Buf = NULL; TmpPtr = StringPtr; while (*StringPtr != L'\0' && *StringPtr != L'&') { StringPtr++; } *Len = StringPtr - TmpPtr; Length = *Len + 1; if (Length < sizeof (StringBuffer) / sizeof (CHAR16)) { Str = StringBuffer; } else { Str = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16)); if (Str == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Exit; } } CopyMem (Str, TmpPtr, *Len * sizeof (CHAR16)); *(Str + *Len) = L'\0'; Length = (*Len + 1) / 2; if (Length <= *NumberSize) { Buf = *Number; ZeroMem (Buf, *NumberSize); } else { Buf = (UINT8 *) AllocateZeroPool (Length); if (Buf == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Exit; } FreePool (*Number); *NumberSize = Length; } Length = *Len; ZeroMem (TemStr, sizeof (TemStr)); for (Index = 0; Index < Length; Index ++) { TemStr[0] = Str[Length - Index - 1]; DigitUint8 = (UINT8) StrHexToUint64 (TemStr); if ((Index & 1) == 0) { Buf [Index/2] = DigitUint8; } else { Buf [Index/2] = (UINT8) ((DigitUint8 << 4) + Buf [Index/2]); } } *Number = Buf; Status = EFI_SUCCESS; Exit: if (Str != StringBuffer && Str != NULL) { FreePool (Str); } return Status; } /** To find the BlockName in the string with same value. @param String Pointer to a Null-terminated Unicode string. @param BlockName Pointer to a Null-terminated Unicode string to search for. @param Buffer Pointer to the value correspond to the BlockName. @param Found The Block whether has been found. @param BufferLen The length of the buffer. @retval EFI_OUT_OF_RESOURCES Insufficient resources to store necessary structures. @retval EFI_SUCCESS The function finishes successfully. **/ EFI_STATUS FindSameBlockElement( IN EFI_STRING String, IN EFI_STRING BlockName, IN UINT8 *Buffer, OUT BOOLEAN *Found, IN UINTN BufferLen ) { EFI_STRING BlockPtr; UINTN Length; UINT8 *TempBuffer; UINTN TempBufferSize; EFI_STATUS Status; TempBufferSize = 10; TempBuffer = AllocateZeroPool (TempBufferSize); if (TempBuffer == NULL) { return EFI_OUT_OF_RESOURCES; } *Found = FALSE; BlockPtr = StrStr (String, BlockName); while (BlockPtr != NULL) { BlockPtr += StrLen (BlockName); Status = GetValueOfNumber (BlockPtr, &TempBuffer, &TempBufferSize, &Length); if (EFI_ERROR (Status)) { return Status; } ASSERT (TempBuffer != NULL); if ((BufferLen == Length) && (0 == CompareMem (Buffer, TempBuffer, Length))) { *Found = TRUE; FreePool (TempBuffer); TempBuffer = NULL; return EFI_SUCCESS; } else { BlockPtr = StrStr (BlockPtr + 1, BlockName); } } FreePool (TempBuffer); return EFI_SUCCESS; } /** Compare the in ConfigAltResp and DefaultAltCfgResp, if the in DefaultAltCfgResp but not in ConfigAltResp,add it to the ConfigAltResp. @param DefaultAltCfgResp Pointer to a null-terminated Unicode string in format. The default value string may contain more than one ConfigAltResp string for the different varstore buffer. @param ConfigAltResp Pointer to a null-terminated Unicode string in format. @param AltConfigHdr Pointer to a Unicode string in format. @param ConfigAltRespChanged Whether the ConfigAltResp has been changed. @retval EFI_OUT_OF_RESOURCES Insufficient resources to store necessary structures. @retval EFI_SUCCESS The function finishes successfully. **/ EFI_STATUS CompareBlockElementDefault ( IN EFI_STRING DefaultAltCfgResp, IN OUT EFI_STRING *ConfigAltResp, IN EFI_STRING AltConfigHdr, IN OUT BOOLEAN *ConfigAltRespChanged ) { EFI_STATUS Status; EFI_STRING BlockPtr; EFI_STRING BlockPtrStart; EFI_STRING StringPtr; EFI_STRING AppendString; EFI_STRING AltConfigHdrPtr; UINT8 *TempBuffer; UINTN TempBufferSize; UINTN OffsetLength; UINTN AppendSize; UINTN TotalSize; BOOLEAN FoundOffset; AppendString = NULL; TempBufferSize = 10; TempBuffer = AllocateZeroPool (TempBufferSize); if (TempBuffer == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Exit; } // // Make BlockPtr point to the first with AltConfigHdr in DefaultAltCfgResp. // AltConfigHdrPtr = StrStr (DefaultAltCfgResp, AltConfigHdr); ASSERT (AltConfigHdrPtr != NULL); if (AltConfigHdrPtr == NULL) { Status = EFI_NOT_FOUND; goto Exit; } BlockPtr = StrStr (AltConfigHdrPtr, L"&OFFSET="); // // Make StringPtr point to the AltConfigHdr in ConfigAltResp. // StringPtr = StrStr (*ConfigAltResp, AltConfigHdr); ASSERT (StringPtr != NULL); while (BlockPtr != NULL) { // // Find the "&OFFSET=" block and get the value of the Number with AltConfigHdr in DefaultAltCfgResp. // BlockPtrStart = BlockPtr; BlockPtr += StrLen (L"&OFFSET="); Status = GetValueOfNumber (BlockPtr, &TempBuffer, &TempBufferSize, &OffsetLength); if (EFI_ERROR (Status)) { Status = EFI_OUT_OF_RESOURCES; goto Exit; } // // To find the same "&OFFSET=" block in ConfigAltResp. // Status = FindSameBlockElement (StringPtr, L"&OFFSET=", TempBuffer, &FoundOffset, OffsetLength); if (EFI_ERROR (Status)) { Status = EFI_OUT_OF_RESOURCES; goto Exit; } if (!FoundOffset) { // // Don't find the same "&OFFSET=" block in ConfigAltResp. // Calculate the size of . // ::='OFFSET=''&WIDTH=''&VALUE='. // BlockPtr = StrStr (BlockPtr + 1, L"&OFFSET="); if (BlockPtr != NULL) { AppendSize = (BlockPtr - BlockPtrStart) * sizeof (CHAR16); } else { AppendSize = StrSize (BlockPtrStart); } // // Copy the to AppendString. // if (AppendString == NULL) { AppendString = (EFI_STRING) AllocateZeroPool (AppendSize + sizeof (CHAR16)); StrnCatS (AppendString, AppendSize / sizeof (CHAR16) + 1, BlockPtrStart, AppendSize / sizeof (CHAR16)); } else { TotalSize = StrSize (AppendString) + AppendSize + sizeof (CHAR16); AppendString = (EFI_STRING) ReallocatePool ( StrSize (AppendString), TotalSize, AppendString ); if (AppendString == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Exit; } StrnCatS (AppendString, TotalSize / sizeof (CHAR16), BlockPtrStart, AppendSize / sizeof (CHAR16)); } } else { // // To find next "&OFFSET=" block with AltConfigHdr in DefaultAltCfgResp. // BlockPtr = StrStr (BlockPtr + 1, L"&OFFSET="); } } if (AppendString != NULL) { // // Reallocate ConfigAltResp to copy the AppendString. // TotalSize = StrSize (*ConfigAltResp) + StrSize (AppendString) + sizeof (CHAR16); *ConfigAltResp = (EFI_STRING) ReallocatePool ( StrSize (*ConfigAltResp), TotalSize, *ConfigAltResp ); if (*ConfigAltResp == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Exit; } StrCatS (*ConfigAltResp, TotalSize / sizeof (CHAR16), AppendString); *ConfigAltRespChanged = TRUE; } Status = EFI_SUCCESS; Exit: if (AppendString != NULL) { FreePool (AppendString); } if (TempBuffer != NULL) { FreePool (TempBuffer); } return Status; } /** Compare the in ConfigAltResp and DefaultAltCfgResp, if the in DefaultAltCfgResp but not in ConfigAltResp,add it to the ConfigAltResp. @param DefaultAltCfgResp Pointer to a null-terminated Unicode string in format. The default value string may contain more than one ConfigAltResp string for the different varstore buffer. @param ConfigAltResp Pointer to a null-terminated Unicode string in format. @param AltConfigHdr Pointer to a Unicode string in format. @param ConfigAltRespChanged Whether the ConfigAltResp has been changed. @retval EFI_OUT_OF_RESOURCES Insufficient resources to store necessary structures. @retval EFI_SUCCESS The function finishes successfully. **/ EFI_STATUS CompareNameElementDefault ( IN EFI_STRING DefaultAltCfgResp, IN OUT EFI_STRING *ConfigAltResp, IN EFI_STRING AltConfigHdr, IN OUT BOOLEAN *ConfigAltRespChanged ) { EFI_STATUS Status; EFI_STRING NvConfigPtr; EFI_STRING NvConfigStart; EFI_STRING NvConfigValuePtr; EFI_STRING StringPtr; EFI_STRING NvConfigExist; EFI_STRING AppendString; CHAR16 TempChar; UINTN AppendSize; UINTN TotalSize; AppendString = NULL; NvConfigExist = NULL; // // Make NvConfigPtr point to the first with AltConfigHdr in DefaultAltCfgResp. // NvConfigPtr = StrStr (DefaultAltCfgResp, AltConfigHdr); ASSERT (NvConfigPtr != NULL); NvConfigPtr = StrStr (NvConfigPtr + StrLen(AltConfigHdr),L"&"); // // Make StringPtr point to the first with AltConfigHdr in ConfigAltResp. // StringPtr = StrStr (*ConfigAltResp, AltConfigHdr); ASSERT (StringPtr != NULL); StringPtr = StrStr (StringPtr + StrLen (AltConfigHdr), L"&"); ASSERT (StringPtr != NULL); if (StringPtr == NULL) { Status = EFI_NOT_FOUND; goto Exit; } while (NvConfigPtr != NULL) { // // ::=