| /** @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; | |
| } | |