/** @file | |
Source file for the component update driver. It parse the update | |
configuration file and pass the information to the update driver | |
so that the driver can perform updates accordingly. | |
Copyright (c) 2002 - 2015, Intel Corporation. All rights reserved.<BR> | |
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 "UpdateDriver.h" | |
/** | |
Copy one line data from buffer data to the line buffer. | |
@param Buffer Buffer data. | |
@param BufferSize Buffer Size. | |
@param LineBuffer Line buffer to store the found line data. | |
@param LineSize On input, size of the input line buffer. | |
On output, size of the actual line buffer. | |
@retval EFI_BUFFER_TOO_SMALL The size of input line buffer is not enough. | |
@retval EFI_SUCCESS Copy line data into the line buffer. | |
**/ | |
EFI_STATUS | |
ProfileGetLine ( | |
IN UINT8 *Buffer, | |
IN UINTN BufferSize, | |
IN OUT UINT8 *LineBuffer, | |
IN OUT UINTN *LineSize | |
) | |
{ | |
UINTN Length; | |
UINT8 *PtrBuf; | |
UINTN PtrEnd; | |
PtrBuf = Buffer; | |
PtrEnd = (UINTN)Buffer + BufferSize; | |
// | |
// 0x0D indicates a line break. Otherwise there is no line break | |
// | |
while ((UINTN)PtrBuf < PtrEnd) { | |
if (*PtrBuf == 0x0D) { | |
break; | |
} | |
PtrBuf++; | |
} | |
if ((UINTN)PtrBuf >= (PtrEnd - 1)) { | |
// | |
// The buffer ends without any line break | |
// or it is the last character of the buffer | |
// | |
Length = BufferSize; | |
} else if (*(PtrBuf + 1) == 0x0A) { | |
// | |
// Further check if a 0x0A follows. If yes, count 0xA | |
// | |
Length = (UINTN) PtrBuf - (UINTN) Buffer + 2; | |
} else { | |
Length = (UINTN) PtrBuf - (UINTN) Buffer + 1; | |
} | |
if (Length > (*LineSize)) { | |
*LineSize = Length; | |
return EFI_BUFFER_TOO_SMALL; | |
} | |
SetMem (LineBuffer, *LineSize, 0x0); | |
*LineSize = Length; | |
CopyMem (LineBuffer, Buffer, Length); | |
return EFI_SUCCESS; | |
} | |
/** | |
Trim Buffer by removing all CR, LF, TAB, and SPACE chars in its head and tail. | |
@param Buffer On input, buffer data to be trimed. | |
On output, the trimmed buffer. | |
@param BufferSize On input, size of original buffer data. | |
On output, size of the trimmed buffer. | |
**/ | |
VOID | |
ProfileTrim ( | |
IN OUT UINT8 *Buffer, | |
IN OUT UINTN *BufferSize | |
) | |
{ | |
UINTN Length; | |
UINT8 *PtrBuf; | |
UINT8 *PtrEnd; | |
if (*BufferSize == 0) { | |
return; | |
} | |
// | |
// Trim the tail first, include CR, LF, TAB, and SPACE. | |
// | |
Length = *BufferSize; | |
PtrBuf = (UINT8 *) ((UINTN) Buffer + Length - 1); | |
while (PtrBuf >= Buffer) { | |
if ((*PtrBuf != 0x0D) && (*PtrBuf != 0x0A ) | |
&& (*PtrBuf != 0x20) && (*PtrBuf != 0x09)) { | |
break; | |
} | |
PtrBuf --; | |
} | |
// | |
// all spaces, a blank line, return directly; | |
// | |
if (PtrBuf < Buffer) { | |
*BufferSize = 0; | |
return; | |
} | |
Length = (UINTN)PtrBuf - (UINTN)Buffer + 1; | |
PtrEnd = PtrBuf; | |
PtrBuf = Buffer; | |
// | |
// Now skip the heading CR, LF, TAB and SPACE | |
// | |
while (PtrBuf <= PtrEnd) { | |
if ((*PtrBuf != 0x0D) && (*PtrBuf != 0x0A ) | |
&& (*PtrBuf != 0x20) && (*PtrBuf != 0x09)) { | |
break; | |
} | |
PtrBuf++; | |
} | |
// | |
// If no heading CR, LF, TAB or SPACE, directly return | |
// | |
if (PtrBuf == Buffer) { | |
*BufferSize = Length; | |
return; | |
} | |
*BufferSize = (UINTN)PtrEnd - (UINTN)PtrBuf + 1; | |
// | |
// The first Buffer..PtrBuf characters are CR, LF, TAB or SPACE. | |
// Now move out all these characters. | |
// | |
while (PtrBuf <= PtrEnd) { | |
*Buffer = *PtrBuf; | |
Buffer++; | |
PtrBuf++; | |
} | |
return; | |
} | |
/** | |
Insert new comment item into comment head. | |
@param Buffer Comment buffer to be added. | |
@param BufferSize Size of comment buffer. | |
@param CommentHead Comment Item head entry. | |
@retval EFI_OUT_OF_RESOURCES No enough memory is allocated. | |
@retval EFI_SUCCESS New comment item is inserted. | |
**/ | |
EFI_STATUS | |
ProfileGetComments ( | |
IN UINT8 *Buffer, | |
IN UINTN BufferSize, | |
IN OUT COMMENT_LINE **CommentHead | |
) | |
{ | |
COMMENT_LINE *CommentItem; | |
CommentItem = NULL; | |
CommentItem = AllocatePool (sizeof (COMMENT_LINE)); | |
if (CommentItem == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
CommentItem->ptrNext = *CommentHead; | |
*CommentHead = CommentItem; | |
// | |
// Add a trailing '\0' | |
// | |
CommentItem->ptrComment = AllocatePool (BufferSize + 1); | |
if (CommentItem->ptrComment == NULL) { | |
FreePool (CommentItem); | |
return EFI_OUT_OF_RESOURCES; | |
} | |
CopyMem (CommentItem->ptrComment, Buffer, BufferSize); | |
*(CommentItem->ptrComment + BufferSize) = '\0'; | |
return EFI_SUCCESS; | |
} | |
/** | |
Add new section item into Section head. | |
@param Buffer Section item data buffer. | |
@param BufferSize Size of section item. | |
@param SectionHead Section item head entry. | |
@retval EFI_OUT_OF_RESOURCES No enough memory is allocated. | |
@retval EFI_SUCCESS Section item is NULL or Section item is added. | |
**/ | |
EFI_STATUS | |
ProfileGetSection ( | |
IN UINT8 *Buffer, | |
IN UINTN BufferSize, | |
IN OUT SECTION_ITEM **SectionHead | |
) | |
{ | |
EFI_STATUS Status; | |
SECTION_ITEM *SectionItem; | |
UINTN Length; | |
UINT8 *PtrBuf; | |
Status = EFI_SUCCESS; | |
// | |
// The first character of Buffer is '[', now we want for ']' | |
// | |
PtrBuf = (UINT8 *)((UINTN)Buffer + BufferSize - 1); | |
while (PtrBuf > Buffer) { | |
if (*PtrBuf == ']') { | |
break; | |
} | |
PtrBuf --; | |
} | |
if (PtrBuf <= Buffer) { | |
// | |
// Not found. Omit this line | |
// | |
return Status; | |
} | |
// | |
// excluding the heading '[' and tailing ']' | |
// | |
Length = PtrBuf - Buffer - 1; | |
ProfileTrim ( | |
Buffer + 1, | |
&Length | |
); | |
// | |
// omit this line if the section name is null | |
// | |
if (Length == 0) { | |
return Status; | |
} | |
SectionItem = AllocatePool (sizeof (SECTION_ITEM)); | |
if (SectionItem == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
SectionItem->ptrSection = NULL; | |
SectionItem->SecNameLen = Length; | |
SectionItem->ptrEntry = NULL; | |
SectionItem->ptrValue = NULL; | |
SectionItem->ptrNext = *SectionHead; | |
*SectionHead = SectionItem; | |
// | |
// Add a trailing '\0' | |
// | |
SectionItem->ptrSection = AllocatePool (Length + 1); | |
if (SectionItem->ptrSection == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// excluding the heading '[' | |
// | |
CopyMem (SectionItem->ptrSection, Buffer + 1, Length); | |
*(SectionItem->ptrSection + Length) = '\0'; | |
return EFI_SUCCESS; | |
} | |
/** | |
Add new section entry and entry value into Section head. | |
@param Buffer Section entry data buffer. | |
@param BufferSize Size of section entry. | |
@param SectionHead Section item head entry. | |
@retval EFI_OUT_OF_RESOURCES No enough memory is allocated. | |
@retval EFI_SUCCESS Section entry is NULL or Section entry is added. | |
**/ | |
EFI_STATUS | |
ProfileGetEntry ( | |
IN UINT8 *Buffer, | |
IN UINTN BufferSize, | |
IN OUT SECTION_ITEM **SectionHead | |
) | |
{ | |
EFI_STATUS Status; | |
SECTION_ITEM *SectionItem; | |
SECTION_ITEM *PtrSection; | |
UINTN Length; | |
UINT8 *PtrBuf; | |
UINT8 *PtrEnd; | |
Status = EFI_SUCCESS; | |
PtrBuf = Buffer; | |
PtrEnd = (UINT8 *) ((UINTN)Buffer + BufferSize - 1); | |
// | |
// First search for '=' | |
// | |
while (PtrBuf <= PtrEnd) { | |
if (*PtrBuf == '=') { | |
break; | |
} | |
PtrBuf++; | |
} | |
if (PtrBuf > PtrEnd) { | |
// | |
// Not found. Omit this line | |
// | |
return Status; | |
} | |
// | |
// excluding the tailing '=' | |
// | |
Length = PtrBuf - Buffer; | |
ProfileTrim ( | |
Buffer, | |
&Length | |
); | |
// | |
// Omit this line if the entry name is null | |
// | |
if (Length == 0) { | |
return Status; | |
} | |
// | |
// Omit this line if no section header has been found before | |
// | |
if (*SectionHead == NULL) { | |
return Status; | |
} | |
PtrSection = *SectionHead; | |
SectionItem = AllocatePool (sizeof (SECTION_ITEM)); | |
if (SectionItem == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
SectionItem->ptrSection = NULL; | |
SectionItem->ptrEntry = NULL; | |
SectionItem->ptrValue = NULL; | |
SectionItem->SecNameLen = PtrSection->SecNameLen; | |
SectionItem->ptrNext = *SectionHead; | |
*SectionHead = SectionItem; | |
// | |
// SectionName, add a trailing '\0' | |
// | |
SectionItem->ptrSection = AllocatePool (PtrSection->SecNameLen + 1); | |
if (SectionItem->ptrSection == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
CopyMem (SectionItem->ptrSection, PtrSection->ptrSection, PtrSection->SecNameLen + 1); | |
// | |
// EntryName, add a trailing '\0' | |
// | |
SectionItem->ptrEntry = AllocatePool (Length + 1); | |
if (SectionItem->ptrEntry == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
CopyMem (SectionItem->ptrEntry, Buffer, Length); | |
*(SectionItem->ptrEntry + Length) = '\0'; | |
// | |
// Next search for '#' | |
// | |
PtrBuf = PtrBuf + 1; | |
Buffer = PtrBuf; | |
while (PtrBuf <= PtrEnd) { | |
if (*PtrBuf == '#') { | |
break; | |
} | |
PtrBuf++; | |
} | |
Length = PtrBuf - Buffer; | |
ProfileTrim ( | |
Buffer, | |
&Length | |
); | |
if (Length > 0) { | |
// | |
// EntryValue, add a trailing '\0' | |
// | |
SectionItem->ptrValue = AllocatePool (Length + 1); | |
if (SectionItem->ptrValue == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
CopyMem (SectionItem->ptrValue, Buffer, Length); | |
*(SectionItem->ptrValue + Length) = '\0'; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Free all comment entry and section entry. | |
@param Section Section entry list. | |
@param Comment Comment entry list. | |
**/ | |
VOID | |
FreeAllList ( | |
IN SECTION_ITEM *Section, | |
IN COMMENT_LINE *Comment | |
) | |
{ | |
SECTION_ITEM *PtrSection; | |
COMMENT_LINE *PtrComment; | |
while (Section != NULL) { | |
PtrSection = Section; | |
Section = Section->ptrNext; | |
if (PtrSection->ptrEntry != NULL) { | |
FreePool (PtrSection->ptrEntry); | |
} | |
if (PtrSection->ptrSection != NULL) { | |
FreePool (PtrSection->ptrSection); | |
} | |
if (PtrSection->ptrValue != NULL) { | |
FreePool (PtrSection->ptrValue); | |
} | |
FreePool (PtrSection); | |
} | |
while (Comment != NULL) { | |
PtrComment = Comment; | |
Comment = Comment->ptrNext; | |
if (PtrComment->ptrComment != NULL) { | |
FreePool (PtrComment->ptrComment); | |
} | |
FreePool (PtrComment); | |
} | |
return; | |
} | |
/** | |
Get section entry value. | |
@param Section Section entry list. | |
@param SectionName Section name. | |
@param EntryName Section entry name. | |
@param EntryValue Point to the got entry value. | |
@retval EFI_NOT_FOUND Section is not found. | |
@retval EFI_SUCCESS Section entry value is got. | |
**/ | |
EFI_STATUS | |
UpdateGetProfileString ( | |
IN SECTION_ITEM *Section, | |
IN UINT8 *SectionName, | |
IN UINT8 *EntryName, | |
OUT UINT8 **EntryValue | |
) | |
{ | |
*EntryValue = NULL; | |
while (Section != NULL) { | |
if (AsciiStrCmp ((CONST CHAR8 *) Section->ptrSection, (CONST CHAR8 *) SectionName) == 0) { | |
if (Section->ptrEntry != NULL) { | |
if (AsciiStrCmp ((CONST CHAR8 *) Section->ptrEntry, (CONST CHAR8 *) EntryName) == 0) { | |
break; | |
} | |
} | |
} | |
Section = Section->ptrNext; | |
} | |
if (Section == NULL) { | |
return EFI_NOT_FOUND; | |
} | |
*EntryValue = (UINT8 *) Section->ptrValue; | |
return EFI_SUCCESS; | |
} | |
/** | |
Convert the dec or hex ascii string to value. | |
@param Str ascii string to be converted. | |
@return the converted value. | |
**/ | |
UINTN | |
UpdateAtoi ( | |
IN UINT8 *Str | |
) | |
{ | |
UINTN Number; | |
Number = 0; | |
// | |
// Skip preceeding while spaces | |
// | |
while (*Str != '\0') { | |
if (*Str != 0x20) { | |
break; | |
} | |
Str++; | |
} | |
if (*Str == '\0') { | |
return Number; | |
} | |
// | |
// Find whether the string is prefixed by 0x. | |
// That is, it should be xtoi or atoi. | |
// | |
if (*Str == '0') { | |
if ((*(Str+1) == 'x' ) || ( *(Str+1) == 'X')) { | |
return AsciiStrHexToUintn ((CONST CHAR8 *) Str); | |
} | |
} | |
while (*Str != '\0') { | |
if ((*Str >= '0') && (*Str <= '9')) { | |
Number = Number * 10 + *Str - '0'; | |
} else { | |
break; | |
} | |
Str++; | |
} | |
return Number; | |
} | |
/** | |
Converts a decimal value to a Null-terminated ascii string. | |
@param Buffer Pointer to the output buffer for the produced Null-terminated | |
ASCII string. | |
@param Value The 64-bit sgned value to convert to a string. | |
@return The number of ASCII characters in Buffer not including the Null-terminator. | |
**/ | |
UINTN | |
UpdateValueToString ( | |
IN OUT UINT8 *Buffer, | |
IN INT64 Value | |
) | |
{ | |
UINT8 TempBuffer[30]; | |
UINT8 *TempStr; | |
UINT8 *BufferPtr; | |
UINTN Count; | |
UINT32 Remainder; | |
TempStr = TempBuffer; | |
BufferPtr = Buffer; | |
Count = 0; | |
if (Value < 0) { | |
*BufferPtr = '-'; | |
BufferPtr++; | |
Value = -Value; | |
Count++; | |
} | |
do { | |
Value = (INT64) DivU64x32Remainder ((UINT64)Value, 10, &Remainder); | |
// | |
// The first item of TempStr is not occupied. It's kind of flag | |
// | |
TempStr++; | |
Count++; | |
*TempStr = (UINT8) ((UINT8)Remainder + '0'); | |
} while (Value != 0); | |
// | |
// Reverse temp string into Buffer. | |
// | |
while (TempStr != TempBuffer) { | |
*BufferPtr = *TempStr; | |
BufferPtr++; | |
TempStr --; | |
} | |
*BufferPtr = 0; | |
return Count; | |
} | |
/** | |
Convert the input value to a ascii string, | |
and concatenates this string to the input string. | |
@param Str Pointer to a Null-terminated ASCII string. | |
@param Number The unsgned value to convert to a string. | |
**/ | |
VOID | |
UpdateStrCatNumber ( | |
IN OUT UINT8 *Str, | |
IN UINTN Number | |
) | |
{ | |
UINTN Count; | |
while (*Str != '\0') { | |
Str++; | |
} | |
Count = UpdateValueToString (Str, (INT64)Number); | |
*(Str + Count) = '\0'; | |
return; | |
} | |
/** | |
Convert the input ascii string into GUID value. | |
@param Str Ascii GUID string to be converted. | |
@param Guid Pointer to the converted GUID value. | |
@retval EFI_OUT_OF_RESOURCES No enough memory is allocated. | |
@retval EFI_NOT_FOUND The input ascii string is not a valid GUID format string. | |
@retval EFI_SUCCESS GUID value is got. | |
**/ | |
EFI_STATUS | |
UpdateStringToGuid ( | |
IN UINT8 *Str, | |
IN OUT EFI_GUID *Guid | |
) | |
{ | |
UINT8 *PtrBuffer; | |
UINT8 *PtrPosition; | |
UINT8 *Buffer; | |
UINTN Data; | |
UINTN StrLen; | |
UINTN Index; | |
UINT8 Digits[3]; | |
StrLen = AsciiStrLen ((CONST CHAR8 *) Str); | |
Buffer = AllocateCopyPool (StrLen + 1, Str); | |
if (Buffer == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// Data1 | |
// | |
PtrBuffer = Buffer; | |
PtrPosition = PtrBuffer; | |
while (*PtrBuffer != '\0') { | |
if (*PtrBuffer == '-') { | |
break; | |
} | |
PtrBuffer++; | |
} | |
if (*PtrBuffer == '\0') { | |
FreePool (Buffer); | |
return EFI_NOT_FOUND; | |
} | |
*PtrBuffer = '\0'; | |
Data = AsciiStrHexToUintn ((CONST CHAR8 *) PtrPosition); | |
Guid->Data1 = (UINT32)Data; | |
// | |
// Data2 | |
// | |
PtrBuffer++; | |
PtrPosition = PtrBuffer; | |
while (*PtrBuffer != '\0') { | |
if (*PtrBuffer == '-') { | |
break; | |
} | |
PtrBuffer++; | |
} | |
if (*PtrBuffer == '\0') { | |
FreePool (Buffer); | |
return EFI_NOT_FOUND; | |
} | |
*PtrBuffer = '\0'; | |
Data = AsciiStrHexToUintn ((CONST CHAR8 *) PtrPosition); | |
Guid->Data2 = (UINT16)Data; | |
// | |
// Data3 | |
// | |
PtrBuffer++; | |
PtrPosition = PtrBuffer; | |
while (*PtrBuffer != '\0') { | |
if (*PtrBuffer == '-') { | |
break; | |
} | |
PtrBuffer++; | |
} | |
if (*PtrBuffer == '\0') { | |
FreePool (Buffer); | |
return EFI_NOT_FOUND; | |
} | |
*PtrBuffer = '\0'; | |
Data = AsciiStrHexToUintn ((CONST CHAR8 *) PtrPosition); | |
Guid->Data3 = (UINT16)Data; | |
// | |
// Data4[0..1] | |
// | |
for ( Index = 0 ; Index < 2 ; Index++) { | |
PtrBuffer++; | |
if ((*PtrBuffer == '\0') || ( *(PtrBuffer + 1) == '\0')) { | |
FreePool (Buffer); | |
return EFI_NOT_FOUND; | |
} | |
Digits[0] = *PtrBuffer; | |
PtrBuffer++; | |
Digits[1] = *PtrBuffer; | |
Digits[2] = '\0'; | |
Data = AsciiStrHexToUintn ((CONST CHAR8 *) Digits); | |
Guid->Data4[Index] = (UINT8)Data; | |
} | |
// | |
// skip the '-' | |
// | |
PtrBuffer++; | |
if ((*PtrBuffer != '-' ) || ( *PtrBuffer == '\0')) { | |
return EFI_NOT_FOUND; | |
} | |
// | |
// Data4[2..7] | |
// | |
for ( ; Index < 8; Index++) { | |
PtrBuffer++; | |
if ((*PtrBuffer == '\0') || ( *(PtrBuffer + 1) == '\0')) { | |
FreePool (Buffer); | |
return EFI_NOT_FOUND; | |
} | |
Digits[0] = *PtrBuffer; | |
PtrBuffer++; | |
Digits[1] = *PtrBuffer; | |
Digits[2] = '\0'; | |
Data = AsciiStrHexToUintn ((CONST CHAR8 *) Digits); | |
Guid->Data4[Index] = (UINT8)Data; | |
} | |
FreePool (Buffer); | |
return EFI_SUCCESS; | |
} | |
/** | |
Pre process config data buffer into Section entry list and Comment entry list. | |
@param DataBuffer Config raw file buffer. | |
@param BufferSize Size of raw buffer. | |
@param SectionHead Pointer to the section entry list. | |
@param CommentHead Pointer to the comment entry list. | |
@retval EFI_OUT_OF_RESOURCES No enough memory is allocated. | |
@retval EFI_SUCCESS Config data buffer is preprocessed. | |
**/ | |
EFI_STATUS | |
PreProcessDataFile ( | |
IN UINT8 *DataBuffer, | |
IN UINTN BufferSize, | |
IN OUT SECTION_ITEM **SectionHead, | |
IN OUT COMMENT_LINE **CommentHead | |
) | |
{ | |
EFI_STATUS Status; | |
CHAR8 *Source; | |
CHAR8 *CurrentPtr; | |
CHAR8 *BufferEnd; | |
CHAR8 *PtrLine; | |
UINTN LineLength; | |
UINTN SourceLength; | |
UINTN MaxLineLength; | |
*SectionHead = NULL; | |
*CommentHead = NULL; | |
BufferEnd = (CHAR8 *) ( (UINTN) DataBuffer + BufferSize); | |
CurrentPtr = (CHAR8 *) DataBuffer; | |
MaxLineLength = MAX_LINE_LENGTH; | |
Status = EFI_SUCCESS; | |
PtrLine = AllocatePool (MaxLineLength); | |
if (PtrLine == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
while (CurrentPtr < BufferEnd) { | |
Source = CurrentPtr; | |
SourceLength = (UINTN)BufferEnd - (UINTN)CurrentPtr; | |
LineLength = MaxLineLength; | |
// | |
// With the assumption that line length is less than 512 | |
// characters. Otherwise BUFFER_TOO_SMALL will be returned. | |
// | |
Status = ProfileGetLine ( | |
(UINT8 *) Source, | |
SourceLength, | |
(UINT8 *) PtrLine, | |
&LineLength | |
); | |
if (EFI_ERROR (Status)) { | |
if (Status == EFI_BUFFER_TOO_SMALL) { | |
// | |
// If buffer too small, re-allocate the buffer according | |
// to the returned LineLength and try again. | |
// | |
FreePool (PtrLine); | |
PtrLine = NULL; | |
PtrLine = AllocatePool (LineLength); | |
if (PtrLine == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
break; | |
} | |
SourceLength = LineLength; | |
Status = ProfileGetLine ( | |
(UINT8 *) Source, | |
SourceLength, | |
(UINT8 *) PtrLine, | |
&LineLength | |
); | |
if (EFI_ERROR (Status)) { | |
break; | |
} | |
MaxLineLength = LineLength; | |
} else { | |
break; | |
} | |
} | |
CurrentPtr = (CHAR8 *) ( (UINTN) CurrentPtr + LineLength); | |
// | |
// Line got. Trim the line before processing it. | |
// | |
ProfileTrim ( | |
(UINT8 *) PtrLine, | |
&LineLength | |
); | |
// | |
// Blank line | |
// | |
if (LineLength == 0) { | |
continue; | |
} | |
if (PtrLine[0] == '#') { | |
Status = ProfileGetComments ( | |
(UINT8 *) PtrLine, | |
LineLength, | |
CommentHead | |
); | |
} else if (PtrLine[0] == '[') { | |
Status = ProfileGetSection ( | |
(UINT8 *) PtrLine, | |
LineLength, | |
SectionHead | |
); | |
} else { | |
Status = ProfileGetEntry ( | |
(UINT8 *) PtrLine, | |
LineLength, | |
SectionHead | |
); | |
} | |
if (EFI_ERROR (Status)) { | |
break; | |
} | |
} | |
// | |
// Free buffer | |
// | |
FreePool (PtrLine); | |
return Status; | |
} | |
/** | |
Parse Config data file to get the updated data array. | |
@param DataBuffer Config raw file buffer. | |
@param BufferSize Size of raw buffer. | |
@param NumOfUpdates Pointer to the number of update data. | |
@param UpdateArray Pointer to the config of update data. | |
@retval EFI_NOT_FOUND No config data is found. | |
@retval EFI_OUT_OF_RESOURCES No enough memory is allocated. | |
@retval EFI_SUCCESS Parse the config file successfully. | |
**/ | |
EFI_STATUS | |
ParseUpdateDataFile ( | |
IN UINT8 *DataBuffer, | |
IN UINTN BufferSize, | |
IN OUT UINTN *NumOfUpdates, | |
IN OUT UPDATE_CONFIG_DATA **UpdateArray | |
) | |
{ | |
EFI_STATUS Status; | |
CHAR8 *Value; | |
CHAR8 *SectionName; | |
CHAR8 Entry[MAX_LINE_LENGTH]; | |
SECTION_ITEM *SectionHead; | |
COMMENT_LINE *CommentHead; | |
UINTN Num; | |
UINTN Index; | |
EFI_GUID FileGuid; | |
SectionHead = NULL; | |
CommentHead = NULL; | |
// | |
// First process the data buffer and get all sections and entries | |
// | |
Status = PreProcessDataFile ( | |
DataBuffer, | |
BufferSize, | |
&SectionHead, | |
&CommentHead | |
); | |
if (EFI_ERROR (Status)) { | |
FreeAllList (SectionHead, CommentHead); | |
return Status; | |
} | |
// | |
// Now get NumOfUpdate | |
// | |
Value = NULL; | |
Status = UpdateGetProfileString ( | |
SectionHead, | |
(UINT8 *) "Head", | |
(UINT8 *) "NumOfUpdate", | |
(UINT8 **) &Value | |
); | |
if (Value == NULL) { | |
FreeAllList (SectionHead, CommentHead); | |
return EFI_NOT_FOUND; | |
} | |
Num = UpdateAtoi((UINT8 *) Value); | |
if (Num <= 0) { | |
FreeAllList (SectionHead, CommentHead); | |
return EFI_NOT_FOUND; | |
} | |
*NumOfUpdates = Num; | |
*UpdateArray = AllocatePool ((sizeof (UPDATE_CONFIG_DATA) * Num)); | |
if (*UpdateArray == NULL) { | |
FreeAllList (SectionHead, CommentHead); | |
return EFI_OUT_OF_RESOURCES; | |
} | |
for ( Index = 0 ; Index < *NumOfUpdates ; Index++) { | |
// | |
// Get the section name of each update | |
// | |
AsciiStrCpyS (Entry, MAX_LINE_LENGTH, "Update"); | |
UpdateStrCatNumber ((UINT8 *) Entry, Index); | |
Value = NULL; | |
Status = UpdateGetProfileString ( | |
SectionHead, | |
(UINT8 *) "Head", | |
(UINT8 *) Entry, | |
(UINT8 **) &Value | |
); | |
if (Value == NULL) { | |
FreeAllList (SectionHead, CommentHead); | |
return EFI_NOT_FOUND; | |
} | |
// | |
// The section name of this update has been found. | |
// Now looks for all the config data of this update | |
// | |
SectionName = Value; | |
// | |
// UpdateType | |
// | |
Value = NULL; | |
Status = UpdateGetProfileString ( | |
SectionHead, | |
(UINT8 *) SectionName, | |
(UINT8 *) "UpdateType", | |
(UINT8 **) &Value | |
); | |
if (Value == NULL) { | |
FreeAllList (SectionHead, CommentHead); | |
return EFI_NOT_FOUND; | |
} | |
Num = UpdateAtoi((UINT8 *) Value); | |
if (( Num >= (UINTN) UpdateOperationMaximum)) { | |
FreeAllList (SectionHead, CommentHead); | |
return Status; | |
} | |
(*UpdateArray)[Index].Index = Index; | |
(*UpdateArray)[Index].UpdateType = (UPDATE_OPERATION_TYPE) Num; | |
// | |
// FvBaseAddress | |
// | |
Value = NULL; | |
Status = UpdateGetProfileString ( | |
SectionHead, | |
(UINT8 *) SectionName, | |
(UINT8 *) "FvBaseAddress", | |
(UINT8 **) &Value | |
); | |
if (Value == NULL) { | |
FreeAllList (SectionHead, CommentHead); | |
return EFI_NOT_FOUND; | |
} | |
Num = AsciiStrHexToUintn ((CONST CHAR8 *) Value); | |
(*UpdateArray)[Index].BaseAddress = (EFI_PHYSICAL_ADDRESS) Num; | |
// | |
// FileBuid | |
// | |
Value = NULL; | |
Status = UpdateGetProfileString ( | |
SectionHead, | |
(UINT8 *) SectionName, | |
(UINT8 *) "FileGuid", | |
(UINT8 **) &Value | |
); | |
if (Value == NULL) { | |
FreeAllList (SectionHead, CommentHead); | |
return EFI_NOT_FOUND; | |
} | |
Status = UpdateStringToGuid ((UINT8 *) Value, &FileGuid); | |
if (EFI_ERROR (Status)) { | |
FreeAllList (SectionHead, CommentHead); | |
return Status; | |
} | |
CopyMem (&((*UpdateArray)[Index].FileGuid), &FileGuid, sizeof(EFI_GUID)); | |
// | |
// FaultTolerant | |
// Default value is FALSE | |
// | |
Value = NULL; | |
(*UpdateArray)[Index].FaultTolerant = FALSE; | |
Status = UpdateGetProfileString ( | |
SectionHead, | |
(UINT8 *) SectionName, | |
(UINT8 *) "FaultTolerant", | |
(UINT8 **) &Value | |
); | |
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) { | |
FreeAllList (SectionHead, CommentHead); | |
return Status; | |
} else if (Value != NULL) { | |
if (AsciiStriCmp ((CONST CHAR8 *) Value, (CONST CHAR8 *) "TRUE") == 0) { | |
(*UpdateArray)[Index].FaultTolerant = TRUE; | |
} else if (AsciiStriCmp ((CONST CHAR8 *) Value, (CONST CHAR8 *) "FALSE") == 0) { | |
(*UpdateArray)[Index].FaultTolerant = FALSE; | |
} | |
} | |
if ((*UpdateArray)[Index].UpdateType == UpdateFvRange) { | |
// | |
// Length | |
// | |
Value = NULL; | |
Status = UpdateGetProfileString ( | |
SectionHead, | |
(UINT8 *) SectionName, | |
(UINT8 *) "Length", | |
(UINT8 **) &Value | |
); | |
if (Value == NULL) { | |
FreeAllList (SectionHead, CommentHead); | |
return EFI_NOT_FOUND; | |
} | |
Num = AsciiStrHexToUintn ((CONST CHAR8 *) Value); | |
(*UpdateArray)[Index].Length = (UINTN) Num; | |
} | |
} | |
// | |
// Now all configuration data got. Free those temporary buffers | |
// | |
FreeAllList (SectionHead, CommentHead); | |
return EFI_SUCCESS; | |
} | |